﻿using System;
using System.Collections.Generic;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;

namespace SharePointRsync
{
    public class SyncJobManager : SPFirstAvailableServiceJobDefinition
    {
        [Persisted]
        private string _webURL = null;

        private List<SPJobDefinition> _matchedSyncJobs = new List<SPJobDefinition>();

        public SyncJobManager()
            : base()
        {
        }

        public SyncJobManager(string jobName, SPService service)
            : base(jobName, service)
        {
        }

        public SyncJobManager(string jobName, SPService service, string weburl)
            : base(jobName, service)
        {
            _webURL = weburl;
        }

        public override void Execute(SPJobState jobState)
        {
            using (SPSite site = new SPSite(_webURL))
            {
                using (SPWeb web = site.OpenWeb())
                {
                    getAllSyncJobs(web);
                    SPListItemCollection listItems = web.Lists["Sync List Timer Management"].Items;

                    foreach (SPListItem item in listItems)
                    {
                        string syncListUrl = new SPFieldUrlValue(item["Sync List"].ToString()).Url;
                        SPList syncList = GetListByUrl(syncListUrl);
                        SPWeb syncListWeb = syncList.ParentWeb;
                        string jobName = "Sync job for " + syncList.Title;

                        SPJobDefinition job = getJob(syncListWeb, jobName);

                        if (job != null)
                        {
                            if (job.LastRunTime.ToLocalTime() < ((DateTime)item["Modified"]).ToLocalTime())
                                setJobSchedule(item, jobName, job);
                        }
                        else
                        {
                            job = new SharePointRsyncJob(jobName, SPFarm.Local.TimerService, syncListWeb.Url, syncList.ID.ToString(), false);
                            setJobSchedule(item, jobName, job);
                        }
                    }
                    deleteRemainingJobs();
                }

            }
        }

        public static SPList GetListByUrl(string listUrl)
        {
            using (SPSite ListSite = new SPSite(listUrl))
            {
                // Check for null
                if (ListSite == null)
                {
                    throw new SPException("Unable to locate site.");
                }

                // Get the List Web
                using (SPWeb ListWeb = ListSite.OpenWeb())
                {
                    // Check for null
                    if (ListWeb == null)
                    {
                        throw new SPException("Unable to open web.");
                    }

                    // Get the List
                    SPList TheList = ListWeb.GetList(listUrl);

                    // Check for null
                    if (TheList == null)
                    {
                        throw new SPException("Unable to find list.");
                    }
                    return TheList;
                }
            }
        }

        private static void setJobSchedule(SPListItem item, string jobName, SPJobDefinition job)
        {
            if ((string)item["Sync Type"] == "Daily")
            {
                SPDailySchedule schedule = new SPDailySchedule();
                schedule.BeginHour = (int)item["Start Hour"];
                schedule.EndHour = (int)item["Start Hour"];
                job.Schedule = schedule;
            }
            else
            {
                SPHourlySchedule schedule = new SPHourlySchedule();
                schedule.BeginMinute = 30;
                schedule.EndMinute = 30;
                job.Schedule = schedule;
            }
            job.Title = jobName;
            job.Update(true);
        }

        private SPJobDefinition getJob(SPWeb web, string jobName)
        {
            foreach (SPJobDefinition job in web.Site.WebApplication.JobDefinitions)
            {
                if (job.Name == jobName)
                {
                    _matchedSyncJobs.Remove(job);
                    return job;
                }
            }
            return null;
        }

        private void getAllSyncJobs(SPWeb web)
        {
            foreach (SPJobDefinition job in web.Site.WebApplication.JobDefinitions)
            {
                if (job.Name.Contains("Sync job for"))
                {
                    _matchedSyncJobs.Add(job);
                }
            }
        }

        private void deleteRemainingJobs()
        {
            foreach (SPJobDefinition job in _matchedSyncJobs)
            {
                job.Delete();
            }
        }
    }
}
